package main

import (
	"fmt"
	"io/ioutil"
	"log"

	"github.com/chai2010/errors"
)

// 错误的包装，同时获取所有的错误，
// 吧容易理解的错误抛出来，根源错误保存起来方便调试
func loadConfig() error {
	_, err := ioutil.ReadFile("/path/to/file")
	if err != nil {
		return errors.Wrap(err, "read failed")
	}
	// ...
	return nil
}

func setup() error {
	err := loadConfig()
	if err != nil {
		return errors.Wrap(err, "invalid config")
	}
	return nil

}

func recvError(ch <-chan string) error {
	p, err := errors.FromJson(<-ch)
	if err != nil {
		log.Fatal(err)
	}
	return p
}

func sendError(ch chan<- string, err error) {
	ch <- errors.ToJson(err)
}

func main() {
	// err := setup()
	// var ch = make(chan string)
	// if err := setup(); err != nil {
	// 	log.Fatal(err)
	// }
	// ------------------------------------------
	// 遍历获取所有包含的错误
	// for i, e := range err.(errors.Error).Wraped() {
	// 	fmt.Printf("wraped(%d):%v\n", i, e)
	// }
	// for i, x := range err.(errors.Error).Caller() {
	// 	fmt.Printf("caller:%d: %s\n", i, x.FuncName)
	// }
	// ------------------------------------------
	// errors.ToJson(err)

	err := errors.NewWithCode(404, "http error code")

	fmt.Println(err)
	fmt.Println(err.(errors.Error).Code())

}

// 剖析异常
// panic支持抛出任意类型的异常（而不仅仅是error类型的错误），recover函数调用的返回值和panic函数的输入参数类型一致，它们的函数签名如下：

// func panic(interface{})
// func recover() interface{}
// Go语言函数调用的正常流程是函数执行返回语句返回结果，在这个流程中是没有异常的，
// 因此在这个流程中执行recover异常捕获函数始终是返回nil。另一种是异常流程:
// 当函数调用panic抛出异常，函数将停止执行后续的普通语句，但是之前注册的defer函数调用仍然保证会被正常执行，
// 然后再返回到的调用者。对于当前函数的调用者，因为处理异常状态还没有被捕获，和直接调用panic函数的行为类似
// 。在异常发生时，如果在defer中执行recover调用，它可以捕获触发panic时的参数，并且恢复到正常的执行流程。
